# from django.contrib.auth.tokens import default_token_generator
import json
from apps.disease_recognition.utils.disease_response import DiseaseResponse
from core.utils.response import Result
from allauth.account.forms import (
    default_token_generator,
)  # 注意！！ token生成实在allauth里面，不是django自带得token生成器
from allauth.account.utils import user_pk_to_url_str
from allauth.account.views import PasswordResetView
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.http import HttpRequest
from django.shortcuts import (
    render,
    get_object_or_404,
    reverse,
    redirect,
    HttpResponseRedirect,
)
from userprofile.forms import UseProfileForm, ResetPasswordForm
from userprofile.models import UserProfile, GENDER_CHOICE
import requests
from disease_recognition.models import DiagnosisHistory
from django.views.decorators.http import require_POST
from django.views.decorators.csrf import csrf_exempt
import logging

logger = logging.getLogger(__name__)

@csrf_exempt # 如果不加这个装饰器，前端请求时会报403错误 因为Django默认开启了CSRF防护
@require_POST
def wechat_mini_program_login(request):
    logging.info(request.body)
    body_data = json.loads(request.body.decode('utf-8')) # 如果是b""的字节流，需要解码，decode而后解析为json数据（即字典）
    code = body_data.get('code') # 微信小程序api传的data在body里面!!
    logging.info(f"后端，请求微信code登录:{code}")
    
    if not code:
        return Result.error(message="缺少code参数")
        # return JsonResponse({"message": "缺少code参数"}, status=400)
    user_info = body_data.get('userInfo')

    # 调用微信 API 获取 openID, openID 是用户在当前小程序的唯一标识
    url = f"https://api.weixin.qq.com/sns/jscode2session?appid={settings.WX_APPID}&secret={settings.WX_SECRET}&js_code={code}&grant_type=authorization_code"
    response = requests.get(url)
    data = response.json()
    # 注意测试要关代理
    logging.info(f"后端，请求微信code登录返回数据: {data}")
    if "openid" in data:
        prefix_openid = "微信小程序用户_" + data["openid"] 
        try:
            user = User.objects.get(username=prefix_openid)
        except User.DoesNotExist:
            # 创建新用户
            user = User.objects.create(username=prefix_openid)
            profile = UserProfile.objects.create(user=user)
            # 从 user_info 填充扩展信息
            profile.gender = GENDER_CHOICE[0][0] if user_info.get("gender", 0) == 0 else GENDER_CHOICE[1][0]
            profile.profile_photo = user_info.get("avatarUrl", "")
            profile.save()      
            logging.info(f"后端，创建新用户，profile: {profile}")

        # 返回用户信息和历史记录
        histories = DiagnosisHistory.objects.filter(
            user=user
        ).values()  # .values() 返回字典
        # from rest_framework_jwt.settings import api_settings

        # # 获取用于生成JWT的处理程序
        # jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        # jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        # # 为用户生成JWT的负载
        # payload = jwt_payload_handler(user)
        # # 使用负载编码生成JWT token
        # token = jwt_encode_handler(payload)
        diagnosisHistory_dict = [DiseaseResponse.create_from_diagnosis_history(histroy) for histroy in histories]
        # 返回包含JWT token和用户历史记录的JSON响应
        return Result.success(data={"token": "jwt_token", "diagnosisHistory": diagnosisHistory_dict, "prefix_openid": prefix_openid},message =  "登录成功")
        # JsonResponse(
        #     {
        #         "token": "jwt_token",
        #         # "token": token,
        #         "diagnosisHistory": list(histories),  # 返回历史记录
        #         "openid": openid,
        #         "message": "登录成功",
        #     }
        # )
    return Result.error(message="获取 openID 失败")
        
    # return JsonResponse({"error": "获取 openID 失败"}, status=400)


@login_required
def profile(request):
    user = request.user
    # print(request.user)
    return render(request, "account/profile.html", {"user": user})


@login_required
def profile_update(request):
    """
    集查看和提交于一体，当查看时处理get，点击button提交提交到本页面，处理post请求
    """
    user = request.user
    user_profile = get_object_or_404(UserProfile, user=user)
    # print(user, 'ok')
    if request.method == "POST":
        # 得到表单数据
        form = UseProfileForm(request.POST)
        # print(form)
        if form.is_valid():
            user_profile.tel = form.cleaned_data["tel"]
            user_profile.gender = form.cleaned_data["gender"]
            # 保存对应文件路径
            user_profile.profile_photo = request.FILES.get("profile_photo")
            print(user_profile.profile_photo)
            user_profile.save()

            return HttpResponseRedirect(reverse("userprofile:profile"))

    else:
        default_data = {
            "tel": user_profile.tel,
            "gender": user_profile.gender,
            "profile_photo": user_profile.profile_photo,
        }

        form = UseProfileForm(default_data)
        # print(form, reverse('userprofile:profile'))
    # 如果时get 返回查看
    return render(request, "account/profile_update.html", {"form": form, "user": user})


class CustomPasswordResetView(PasswordResetView):
    def post(self, request, *args, **kwargs):
        reset_password_form = ResetPasswordForm(request.POST)
        if reset_password_form.is_valid():
            # 从电话筛选出 用户对象
            tel = reset_password_form.clean_identity_tel()
            # UseProfile 中由于user相同属性的 username
            try:
                username = UserProfile.objects.get(tel=tel)
                user = User.objects.get(username=username)
            except:
                return render(
                    request,
                    "account/telephone_error.html",
                    {"content": "电话错误(表单格式错误）或和他人一样！"},
                )
            # 查看传参有无 令牌
            token_generator = kwargs.get("token_generator", default_token_generator)
            # 没有生成token
            temp_key = token_generator.make_token(user)
            # 反向解析路径，（并传令牌参数）
            path = reverse(
                "account_reset_password_from_key",
                kwargs=dict(uidb36=user_pk_to_url_str(user), key=temp_key),
            )  # ^password/reset/key/(?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+)/$ [name='account_reset_password_from_key']
            # 在根目录下建立绝对路径(self = request)
            url = HttpRequest.build_absolute_uri(request, path)
            # 重定向至修改密码链接
            print(request, url, path)
            return redirect(url)

        else:
            return render(
                request,
                "account/telephone_error.html",
                {"content": "电话错误(表单格式错误）"},
            )


# 注意 这里不能加上 login_required 的限制！ 不然登录页面 忘记密码就会无法登录
password_reset = CustomPasswordResetView.as_view()
